﻿/*******************************************************************************
 * Copyright © Chris Watson 2013                                               *
 *                                                                             *
 * This document is a part of the source code and related artefacts for Chris  *
 * Watson's Desktop Wallpaper Guard, a software application which will detect  *
 * when another process removes the wallpaper from a Windows desktop and       *
 * restore an image of the user's choice.                                      *
 *                                                                             *
 * Author:                                                                     *
 *   Chris Watson       [mailto:chris@watson.me.uk]                            *
 * Date:                                                                       *
 *   17 August 2013                                                            *
 ******************************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace Watson.BleaknessEliminator
{
    /// <summary>
    /// Helper class for setting and retrieving Windows profile settings.
    /// </summary>
    internal static class WindowsProfileSettings
    {
        #region Internal Methods

        /// <summary>
        /// Gets the desktop wallpaper for the current user profile.
        /// </summary>
        /// <returns>
        /// System.String
        /// <para>
        /// The path to the desktop wallpaper file.
        /// </para>
        /// </returns>
        /// <exception cref="System.ComponentModel.Win32Exception">
        /// Failed to obtain desktop wallpaper.
        /// </exception>
        internal static string GetWallpaper()
        {
            /*
             * Get path to current desktop wallpaper file.
             * Ref: http://www.dreamincode.net/forums/topic/124884-get-current-d
             *      esktop-wallpaper-resolved/
             */
            
            const int maxPath = 260;

            string path = new string('\0', maxPath);

            bool sysParamInfoRet = 
                NativeMethods.SystemParametersInfo(
                    NativeMethods.SPI_GETDESKWALLPAPER,
                    path.Length,
                    path,
                    0);

            if (!sysParamInfoRet)
            {
                Win32Exception win32Exception = new Win32Exception();

                Trace.TraceError("{0} {1}: {2}",
                    DateTime.Now, win32Exception.GetType().FullName,
                    win32Exception.Message);

                throw win32Exception;
            }

            path = path.Substring(0, path.IndexOf('\0'));
            
            return path;
        }


        /// <summary>
        /// Sets the desktop wallpaper for the current user profile.
        /// </summary>
        /// <param name="path">
        /// The path to the desktop wallpaper file.
        /// </param>
        /// <exception cref="System.ArgumentNullException">
        /// <paramref name="path"/> was <c>null</c>.
        /// </exception>
        /// <exception cref="System.ArgumentException">
        /// <paramref name="path"/> was empty or consisted entirely of
        /// whitespace.
        /// </exception>
        /// <exception cref="System.ComponentModel.Win32Exception">
        /// Failed to set desktop wallpaper.
        /// </exception>
        internal static void SetWallpaper(string path)
        {
            /*
             * Parameter validation.
             */

            if (path == null)
            {
                throw new ArgumentNullException("path");
            }
            else if(String.IsNullOrWhiteSpace(path))
            {
                throw new ArgumentException(
                    "Argument cannot be an empty string.", "path");
            }


            /*
             * Main work.
             */

            Trace.TraceInformation("{0} Setting desktop wallpaper to '{1}'.",
                DateTime.Now, path);
            
            /*
             * Set wallpaper.
             * Ref: http://stackoverflow.com/questions/7860619/wallpaper-changin
             *      g-on-windows-7
             */
            bool sysParamInfoRet = 
                NativeMethods.SystemParametersInfo(
                    NativeMethods.SPI_SETDESKWALLPAPER,
                    0,
                    path,
                    NativeMethods.SPIF_UPDATEINIFILE |
                    NativeMethods.SPIF_SENDWININICHANGE);

            if (!sysParamInfoRet)
            {
                Win32Exception win32Exception = new Win32Exception();

                Trace.TraceError("{0} {1}: {2}",
                    DateTime.Now, win32Exception.GetType().FullName,
                    win32Exception.Message);

                throw win32Exception;
            }
        }


        /// <summary>
        /// Sets the desktop wallpaper for the current user profile if the
        /// specified path is different from the desktop wallpaper that is
        /// currently set.
        /// </summary>
        /// <param name="path">
        /// The path to the desktop wallpaper file.
        /// </param>
        /// <exception cref="System.ArgumentNullException">
        /// <paramref name="path"/> was <c>null</c>.
        /// </exception>
        /// <exception cref="System.ArgumentException">
        /// <paramref name="path"/> was empty or consisted entirely of
        /// whitespace.
        /// </exception>
        internal static void SetWallpaperIfDifferent(string path)
        {
            /*
             * Parameter validation.
             */

            if (path == null)
            {
                throw new ArgumentNullException("path");
            }
            else if (String.IsNullOrWhiteSpace(path))
            {
                throw new ArgumentException(
                    "Argument cannot be an empty string.", "path");
            }


            /*
             * Main work.
             */

            string currentPath = GetWallpaper();

            bool differentPath = 
                !String.Equals(currentPath, path, 
                               StringComparison.OrdinalIgnoreCase);
            
            if (differentPath)
            {
                SetWallpaper(path);
            }
            else
            {
                Trace.TraceInformation(
                    "{0} Ignoring request to set desktop wallpaper. It is"
                    + " already set to '{1}'.",
                    DateTime.Now, path);
            }
        }

        #endregion
    }
}
